#include "staralgorithm.h"

ListNode StarAlgorithm::Open;
ListNode StarAlgorithm::Close;

StarAlgorithm::~StarAlgorithm() {
    clearNodes();
    delete Final;
   // std::cout<<"LIMPANDO A ESTRELA 8" << std::endl;
}


StarAlgorithm::StarAlgorithm(const Maze &M_)
{
    M = M_;
    Inicial = new Node(M.getInicial());
    Final = new Node(M.getFinal());
    pesoVertical = pesoHorizontal = pesoDiagonal = 1;
    resolved = false;
    showLists = true;
}

Node *StarAlgorithm::find(ListNode::iterator Begin,ListNode::iterator End, Node n){
    for(ListNode::iterator i = Begin; i != End; i++){
        if(**i == n){
            return *i;
        }
    }
    return NULL;
}

void StarAlgorithm::SetParams(const Maze &M_) {
    M = M_;
    delete Final;
    Inicial = new Node(M.getInicial());
    Final = new Node(M.getFinal());
    clearNodes();
    resolved = false;
}

void StarAlgorithm::clearNodes() {
    while(!Open.empty()){
        delete Open.back();
        Open.pop_back();
    }
    while(!Close.empty()){
        delete Close.back();
        Close.pop_back();
    }
    Close.clear();
    Open.clear();
}

void StarAlgorithm::AddNode(Node ToAdd, Node *Parent) {
    Node *resp;
    resp = find(Open.begin(),Open.end(),ToAdd);
    if(resp != NULL){
        if(resp->getCost() > ToAdd.getCost() && Parent != resp){
            *resp = ToAdd;
        }
    } else {
        resp = find(Close.begin(),Close.end(),ToAdd);
        if(resp != NULL){
            if(resp->getCost() > ToAdd.getCost() && Parent != resp){
                    //*resp = ToAdd;
            }
        } else {
            Node *tmp = new Node(ToAdd);
            Open.push_back(tmp);
            M.setSaddles(tmp->row,tmp->col,OPEN);
        }
    }
}

void StarAlgorithm::printOpen(){
    std::cout << "Lista Open = ";
    for(ListNode::iterator i = Open.begin(); i != Open.end(); i++){
        std::cout << **i;
    }
    std::cout << std::endl;
}


void StarAlgorithm::printClose(){
    std::cout << "Lista Close = ";
    for(ListNode::iterator i = Close.begin(); i != Close.end(); i++){
        std::cout << **i;
    }
    std::cout << std::endl;
}


void StarAlgorithm::expandNode(Node *n){
    Node Tmp;
    Close.push_back(n);
    Tmp = *n;
    M.setSaddles(Tmp.row,Tmp.col,CLOSE);
    for(int i = n->col-1;i <= n->col + 1;i++){
        for(int j = n->row - 1; j <= n->row+1; j++){
            if((i == n->col && j == n->row) ||
               i < 0 || i > M.col-1 ||
               j < 0 || j > M.row-1 || M.getSaddles(j,i) == WALL)
                continue;

            if(i == Tmp.col){
                Tmp.g = pesoVertical + n->g;
            } else if(j == Tmp.row) {
                Tmp.g = pesoHorizontal + n->g;
            } else {
                Tmp.g = pesoDiagonal + n->g;
            }

            Tmp.parent = n;
            Tmp.row = j;
            Tmp.col = i;
            Tmp.h = sqrt(pow(Tmp.row - M.getFinal().row,2) * pesoHorizontal
                         +pow(Tmp.col - M.getFinal().col,2) * pesoVertical);
            AddNode(Tmp,n->parent);
            Tmp = *n;
        }
    }
}

Node *StarAlgorithm::Start() {
    Node *Tmp;
    Inicial->h = sqrt(pow(Inicial->row - M.getFinal().row,2) * pesoHorizontal
                      +pow(Inicial->col - M.getFinal().col,2) * pesoVertical);
    Open.push_back(Inicial);
    while(!Open.empty()){
        sort(Open.begin(),Open.end(),NodeLess());
        Tmp = Open.front();
        Open.erase(Open.begin());
        if(*Tmp == *Final){
            printResp(Tmp);
            return Tmp;
        }
        expandNode(Tmp);
    }
    printf("FALHA\n");
    return NULL;
}


void StarAlgorithm::printResp(Node *n) {
    resolved = true;
    while(n != NULL){
        if(n != Inicial)
            M.setSolution(n->row,n->col);
        n = n->parent;
    }
}


void StarAlgorithm::updateGraph(){
    NodeGraphics *tmp = NULL;
    for(int i = 0; i < M.row; i++) {
        for(int j = 0; j < M.col; j++){
            tmp = NodeGraphics::NodesMap[pair(i,j)];
            if((M.getSaddles(i,j) == CLOSE || M.getSaddles(i,j) == OPEN) && !showLists)
                tmp->setType(EMPTY);
            else
                tmp->setType((LAB)M.getSaddles(i,j));
            tmp->update();
        }
    }
}

void StarAlgorithm::showHideLists() {
    showLists = !showLists;
}

int StarAlgorithm::printParc(int row, int col) {
    Node *resp = NULL;
    Node n(row,col);
    resp = find(Open.begin(),Open.end(),n);
    if(resp == NULL)
        resp = find(Close.begin(),Close.end(),n);

    if(resp == NULL)
        return 0;

    while(resp != NULL) {
        if(resp == Inicial || *resp == M.getFinal()){
            resp->graph->setType(INIT);
            resp->graph->update();
            resp = resp->parent;
            continue;
        }
        LAB tmp = resp->graph->type;
        resp->graph->setType(CAM_TMP);
        resp->graph->update();
        resp = resp->parent;
        resp->graph->setType(tmp);
    }
    return 1;
}


void StarAlgorithm::setPesoHorizontal(double p) {
    pesoHorizontal = p;
}

void StarAlgorithm::setPesoVertical(double p){
    pesoVertical = p;
}

void StarAlgorithm::setPesoDiagonal(double p){
    pesoDiagonal = p;
}

Node *StarAlgorithm::find(int row, int col) {
    Node *resp = NULL;
    Node n(row,col);
    resp = find(Open.begin(),Open.end(),n);
    if(resp != NULL)
        return resp;
    resp = find(Close.begin(),Close.end(),n);
    return resp;
}






